package com.ruoyi.tb.lmt.controller;

import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.system.domain.vo.SysOssVo;
import com.ruoyi.system.service.ISysOssService;
import com.ruoyi.tb.lmt.domain.bo.*;
import com.ruoyi.tb.lmt.domain.vo.DrDamperDataVo;
import com.ruoyi.tb.lmt.domain.vo.OilSampleDetectionVo;
import com.ruoyi.tb.lmt.service.*;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 试验台相关数据
 * @author: jiaxiufeng
 * @description:
 * @create: 2023/12/28 14:35
 **/
@SaIgnore
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/sytdata")
public class SytDataController {
    @Autowired
    ISytDataService sytDataService;

    @Autowired
    private IElectronicPendulumDataService iElectronicPendulumDataService;

    @Autowired
    private IElectronicPendulumdetailDataService iElectronicPendulumdetailDataService;

    @Autowired
    private IOilSampleDetectionService iOilSampleDetectionService;

    @Autowired
    private ISysOssService iSysOssService;

    @Autowired
    private IClientFileService iClientFileService;

    @RequestMapping("/readExcel")
    public R<JSONArray> readExcel() throws FileNotFoundException {
        return R.ok(sytDataService.readExcel());
    }

    @RequestMapping("/readExcelById")
    public R<JSONObject> readExcelById(String id) throws FileNotFoundException {
        return R.ok(sytDataService.readExcelById(id));
    }
    @RequestMapping("/readDamper")
    public R<List<DrDamperDataVo>> readDamperByDrCarNo(String drCarNo) throws FileNotFoundException {
        return R.ok(sytDataService.readDamperByDrCarNo(drCarNo));
    }

    /**
     * @description: 测试整个试验台数据看流程
     * @author jiaxiufeng
     * @date 2024/1/10 13:38
     * @version 1.0
     */
    @RequestMapping("/execSytJob")
    public R<JSONArray> execSytJob() throws FileNotFoundException, JsonProcessingException {
        return R.ok(sytDataService.execSytJob());
    }

    /**
     * @description: 获取油样数据
     * @author jiaxiufeng
     * @date 2024/1/15 09:21
     * @version 1.0
     */
    @RequestMapping("/getOilSampleData")
    public R<List<OilSampleDetectionVo>> getOilSampleData(String oilId,String startDate,String endDate,String oilType) throws FileNotFoundException {
        return R.ok(sytDataService.getOilSampleData(oilId,startDate,endDate,oilType));
    }

    @GetMapping("/selectOil")
    public TableDataInfo<OilSampleDetectionVo> selectOil(String lmtNumber,String oilType,PageQuery pageQuery) {
        return sytDataService.selectOil(lmtNumber,oilType, pageQuery);
    }
    @GetMapping("/selectOilList")
    public TableDataInfo<OilSampleDetectionVo> selectOil1(String lmtNumber,String oilType,PageQuery pageQuery) {
        return sytDataService.selectOilTable(lmtNumber,oilType, pageQuery);
    }

    @GetMapping("/selectOilDate")
    public OilSampleDetectionVo selectOilDate(String lmtNumber,String oilType,String oilData) {
        return sytDataService.selectOilDate(lmtNumber,oilType,oilData);
    }

    @GetMapping("/selectDamperData")
    public TableDataInfo<DrDamperDataVo> selectDamperData(String drDamperNo,String drDamperType,String drCarNo,PageQuery pageQuery) {
        return sytDataService.selectDamperData(drDamperNo,drDamperType,drCarNo,pageQuery);
    }

    @GetMapping("/selectOilById")
    public OilSampleDetectionVo selectOilById(Long id) {
        return sytDataService.selectOilById(id);
    }

    /**
     *  油样导入
     * @return
     */
    @PostMapping("/oil/upload")
    public R oilUpload(MultipartFile file) throws IOException {
        List<String> strs = readLines(file);
        for (String str : strs) {
            OilSampleDetectionBo bo = getBoByString(str);
            iOilSampleDetectionService.insertByBo(bo);
        }
        return R.ok();
    }

    public OilSampleDetectionBo getBoByString(String str){
        String[] strs = str.replace(" ","").split(",");
        OilSampleDetectionBo bo = new OilSampleDetectionBo();
        bo.setOilId(strs[49]);
        bo.setDjNo(strs[49]);
        bo.setOilType(strs[50]);
        bo.setOilFe(strs[1]);
        bo.setOilCr(strs[3]);
        bo.setOilPb(strs[5]);
        bo.setOilCu(strs[7]);
        bo.setOilSn(strs[9]);
        bo.setOilAl(strs[11]);
        bo.setOilNi(strs[13]);
        bo.setOilAg(strs[15]);
        bo.setOilSi(strs[17]);
        bo.setOilB(strs[19]);
        bo.setOilNa(strs[21]);
        bo.setOilMg(strs[23]);
        bo.setOilCa(strs[25]);
        bo.setOilBa(strs[27]);
        bo.setOilP(strs[29]);
        bo.setOilZn(strs[31]);
        bo.setOilMo(strs[33]);
        bo.setOilTi(strs[35]);
        bo.setOilV(strs[37]);
        bo.setOilMn(strs[39]);
        bo.setOilCd(strs[41]);
        bo.setOilH(strs[43]);
        bo.setOilC(strs[45]);
        bo.setOilData(strs[47]);
        bo.setBurnMode(strs[53]);
        return bo;
    }

    public List<String> readLines(MultipartFile file) throws IOException {
        List<String> lines = new ArrayList<>();
        BufferedReader reader = new BufferedReader(new InputStreamReader(file.getInputStream()));
        String line;
        while ((line = reader.readLine()) != null) {
            lines.add(line);
        }
        reader.close();
        return lines;
    }

    @GetMapping("/selectDamperDataById")
    public DrDamperDataVo selectDamperDataById(Long id) {
        return sytDataService.selectDamperDataById(id);
    }


    @PostMapping("/addData")
    public R<Void> addData(@Validated(AddGroup.class) @RequestBody JSONArray tableVos) {
        System.out.println("Received data: " + tableVos);
        for (int i = 0; i < tableVos.size(); i++) {
            JSONObject tableVo = tableVos.getJSONObject(i);
            String tableName = tableVo.getStr("tableName");
            JSONArray lines = tableVo.getJSONArray("lines");
            processTableData(tableName, lines);
        }
        return R.ok();
    }

    private void processTableData(String tableName, JSONArray lines) {
        switch (tableName) {
            case "_MCGS":
                sytDataService.insertMcgs0000(lines);
                break;
            case "MCGS_AlarmInfo":
                sytDataService.insertMcgs0001(lines);
                break;
            case "QJ1气动集成组_MCGS":
                sytDataService.insertMcgs0002(lines);
                break;
            case "QK1气控阀组_MCGS":
                sytDataService.insertMcgs0003(lines);
                break;
            case "中继阀组_MCGS":
                sytDataService.insertMcgs0004(lines);
                break;
            case "分配阀109E作用部组_MCGS":
                sytDataService.insertMcgs0005(lines);
                break;
            case "分配阀109E均衡部组_MCGS":
                sytDataService.insertMcgs0006(lines);
                break;
            case "分配阀109E组_MCGS":
                sytDataService.insertMcgs0007(lines);
                break;
            case "分配阀组_MCGS":
                sytDataService.insertMcgs0008(lines);
                break;
            case "小闸组_MCGS":
                sytDataService.insertMcgs0009(lines);
                break;
            case "小闸组1_MCGS":
                sytDataService.insertMcgs0010(lines);
                break;
            case "紧急阀1组_MCGS":
                sytDataService.insertMcgs0011(lines);
                break;
            case "紧急阀2组_MCGS":
                sytDataService.insertMcgs0012(lines);
                break;
            case "紧急阀组_MCGS":
                sytDataService.insertMcgs0013(lines);
                break;
            case "装车号组_MCGS":
                sytDataService.insertMcgs0014(lines);
                break;
            case "遮断阀组_MCGS":
                sytDataService.insertMcgs0015(lines);
                break;
            default:
                System.out.println("No valid table found for name: " + tableName);
                break;
        }
    }

    // 添加电子摆动数据
    @PostMapping("/addElePendulumData")
    public R<Void> addElePendulumData(@Validated(AddGroup.class) @RequestBody List<ElectronicPendulumDataBo> dataList) {
        for (ElectronicPendulumDataBo data : dataList) {
            // 保存 ElectronicPendulumDataBo 到数据库
            String lmtId = data.getLmtId();
            String testDate = data.getTestDate();
            //根据lmtId和testDate查询数据库中是否存在该数据，如果存在就跳过这条数据，如果不存在就执行插入操作
            if (!iElectronicPendulumDataService.queryExistsByLmtIdAndTestDate(lmtId, testDate)) {
                data.setCreateBy("admin");
                data.setUpdateBy("admin");
                iElectronicPendulumDataService.insertByBo(data);

                //保存 ElectronicPendulumdetailDataBo 到数据库
                for (Map.Entry<Object, Object> entry : data.getDisplacementDataDetail().entrySet()) {
                    // 获取每个 entry 的值
                    Object value = entry.getValue();
                    if (value instanceof Map) {
                        Map<String, Object> displacementData = (Map<String, Object>) value;
                        ElectronicPendulumdetailDataBo electronicPendulumdetailDataBo = new ElectronicPendulumdetailDataBo();
                        // 将 displacementData 中的值设置到 electronicPendulumdetailDataBo 中
                        electronicPendulumdetailDataBo.setLimitErrorReverse(String.valueOf(displacementData.get("limitErrorReverse")));
                        electronicPendulumdetailDataBo.setDisplacementAndTheoreticalValueL(String.valueOf(displacementData.get("displacementAndTheoreticalValueL")));
                        electronicPendulumdetailDataBo.setLinearityPositive(String.valueOf(displacementData.get("linearityPositive")));
                        electronicPendulumdetailDataBo.setGapError(String.valueOf(displacementData.get("gapError")));
                        electronicPendulumdetailDataBo.setLimitErrorPositive(String.valueOf(displacementData.get("limitErrorPositive")));
                        electronicPendulumdetailDataBo.setReportNumber(String.valueOf(displacementData.get("reportNumber")));
                        electronicPendulumdetailDataBo.setLmtId(String.valueOf(displacementData.get("lmtId")));
                        electronicPendulumdetailDataBo.setDisplacementAndTheoreticalValueU(String.valueOf(displacementData.get("displacementAndTheoreticalValueU")));
                        electronicPendulumdetailDataBo.setMeasuredValuePositive(String.valueOf(displacementData.get("measuredValuePositive")));
                        electronicPendulumdetailDataBo.setMeasuredValueReverse(String.valueOf(displacementData.get("measuredValueReverse")));
                        electronicPendulumdetailDataBo.setLinearityReverse(String.valueOf(displacementData.get("linearityReverse")));
                        electronicPendulumdetailDataBo.setTestDate(String.valueOf(displacementData.get("testDate")));
                        electronicPendulumdetailDataBo.setCreateBy("admin");
                        electronicPendulumdetailDataBo.setUpdateBy("admin");

                        // 执行插入操作
                        iElectronicPendulumdetailDataService.insertByBo(electronicPendulumdetailDataBo);
                    }
                }
            } else {
                continue;
            }

        }
        return R.ok();
    }

    @PostMapping("/addTxtData")
    public R<Void> addTxtData(@Validated(AddGroup.class) @RequestBody JSONArray dataArray) {
        System.out.println("Received data: " + dataArray);
        // 循环处理解析后的数据
        for (Object obj : dataArray) {
            JSONObject jsonObj = (JSONObject) obj;

            // 创建 OilSampleDetectionBo 对象
            OilSampleDetectionBo bo = new OilSampleDetectionBo();
            String oilDate = (String) jsonObj.get("oil_date");
            bo.setOilData(oilDate);
            String oilType = (String) jsonObj.get("oil_type");
            String oilId = (String) jsonObj.get("dj_no");
            bo.setOilId(oilId);
            bo.setDjNo(oilId);
            bo.setOilType(oilType);
            bo.setBurnMode((String) jsonObj.get("burn_mode"));
            bo.setOilFe((String) jsonObj.get("oil_fe"));
            bo.setOilMg((String) jsonObj.get("oil_mg"));
            bo.setOilH((String) jsonObj.get("oil_h"));
            bo.setOilBa((String) jsonObj.get("oil_ba"));
            bo.setOilNi((String) jsonObj.get("oil_ni"));
            bo.setOilAl((String) jsonObj.get("oil_al"));
            bo.setOilAg((String) jsonObj.get("oil_ag"));
            bo.setOilP((String) jsonObj.get("oil_p"));
            bo.setOilV((String) jsonObj.get("oil_v"));
            bo.setOilMn((String) jsonObj.get("oil_mn"));
            bo.setOilZn((String) jsonObj.get("oil_zn"));
            bo.setOilSi((String) jsonObj.get("oil_si"));
            bo.setOilTi((String) jsonObj.get("oil_ti"));
            bo.setOilNa((String) jsonObj.get("oil_na"));
            bo.setOilMo((String) jsonObj.get("oil_mo"));
            bo.setOilB((String) jsonObj.get("oil_b"));
            bo.setOilC((String) jsonObj.get("oil_c"));
            bo.setOilCa((String) jsonObj.get("oil_ca"));
            bo.setOilCd((String) jsonObj.get("oil_cd"));
            bo.setOilCr((String) jsonObj.get("oil_cr"));
            bo.setOilCu((String) jsonObj.get("oil_cu"));
            bo.setOilPb((String) jsonObj.get("oil_pb"));
            bo.setOilSn((String) jsonObj.get("oil_sn"));
            bo.setDelFlag("0");
            bo.setCreateBy("admin");
            bo.setUpdateBy("admin");
            if (!iOilSampleDetectionService.queryExistsByLmtIdAndTestDate(oilDate, oilId,oilType)) {
                // 执行插入操作
                iOilSampleDetectionService.insertByBo(bo);
            }else {
                continue;
            }
        }
        return R.ok();
    }

    @PostMapping("/upload")
    public R<Void> upload(@RequestParam("file") MultipartFile file) throws IOException {
        if (file.isEmpty()) {
            return R.fail("上传的文件为空");
        }

        // 获取文件名
        String originalFilename = file.getOriginalFilename();

        // 读取文件内容
        byte[] fileBytes = file.getBytes();

        // 调用方法上传文件并保存相关信息到数据库
        SysOssVo sysOssVo = iSysOssService.uploadBackups(originalFilename,"", fileBytes);

        if (sysOssVo != null) {
            //先通过sysOssVo.getOriginalName()判断这个文件之前是否存在，存在就不进行添加不存在就添加
            if (!iClientFileService.queryByOriginalName(sysOssVo.getOriginalName()) ) {
                // 构建 ClientFileBo 对象并保存到数据库
                ClientFileBo temp = new ClientFileBo();
                temp.setOriginalName(sysOssVo.getOriginalName());
                temp.setFileName(sysOssVo.getFileName());
                temp.setFileSuffix(sysOssVo.getFileSuffix());
                temp.setUrl(sysOssVo.getUrl());
                temp.setService(sysOssVo.getService());
                temp.setDjNo("C1001");
                temp.setCreateBy("admin");
                temp.setUpdateBy("admin");
                iClientFileService.insertByBo(temp);

            }
            return R.ok("文件上传成功并保存信息到数据库");
        } else {
            return R.fail("文件上传失败");
        }
    }

    @PostMapping("/addDrDamperData")
    public R<Void> addDrDamperData(@Validated(AddGroup.class) @RequestBody JSONArray tableVos) {
        System.out.println("Received data: " + tableVos);
        for (int i = 0; i < tableVos.size(); i++) {
            JSONObject tableVo = tableVos.getJSONObject(i);
            String tableName = tableVo.getStr("tableName");
            JSONArray lines = tableVo.getJSONArray("lines");
            sytDataService.insertDrDamperData(lines);
        }
        return R.ok();
    }

    @PostMapping("/oil/export")
    public void export(String lmtNumber, HttpServletResponse response) {
        // 创建一个Calendar实例
        Calendar calendar = Calendar.getInstance();

        // 将时间设置为当前时间
        calendar.setTime(new Date());

        // 减去30天来设置日期为前一个月
        calendar.add(Calendar.DATE, -30);

        // 设置时分秒为午夜00:00:00
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);

        // 从Calendar实例获取修改后的时间
        Date startDate = calendar.getTime();
        Date endDate = new Date();

        List<OilSampleDetectionVo> list = iOilSampleDetectionService.selectOilByLmtNumber(lmtNumber, startDate, endDate);

        if (list.size() < 1) {
            throw new RuntimeException("该车号一个月内无油样试验");
        }
        // 根据 oil_type 进行排序
        Collections.sort(list, Comparator.comparing(OilSampleDetectionVo::getOilType));

        // 创建新的列表来存储计算后的平均值数据
        List<OilSampleDetectionVo> averagedList = new ArrayList<>();

        // 遍历原始数据列表
        String currentOilType = null;
        int count = 0;
        Map<String, Double> sumMap = new HashMap<>(); // 用于存储每个字段的总和
        for (OilSampleDetectionVo vo : list) {
            if (!vo.getOilType().equals(currentOilType)) {
                // 当前部位的 oil_type 与前一个不同，表示新的部位开始，需要计算平均值并添加到新列表中
                if (count > 0) {
                    // 计算平均值
                    OilSampleDetectionVo averagedVo = calculateAverage(currentOilType, sumMap, count);
                    averagedList.add(averagedVo);
                }
                // 重置状态
                currentOilType = vo.getOilType();
                sumMap.clear();
                count = 0;
            }
            // 累加各字段的值
            accumulateFields(vo, sumMap);
            count++;
        }

        // 处理最后一个部位的数据
        if (count > 0) {
            OilSampleDetectionVo averagedVo = calculateAverage(currentOilType, sumMap, count);
            averagedList.add(averagedVo);
        }
        // 合并原始数据列表和平均值列表
        List<OilSampleDetectionVo> combinedList = new ArrayList<>(list);
        combinedList.addAll(averagedList);

        Collections.sort(combinedList, Comparator.comparing(OilSampleDetectionVo::getOilType));

        ExcelUtil.exportExcel(combinedList, lmtNumber+"车油样数据报表", OilSampleDetectionVo.class, response);
    }

    // 计算平均值
    private OilSampleDetectionVo calculateAverage(String oilType, Map<String, Double> sumMap, int count) {
        OilSampleDetectionVo averagedVo = new OilSampleDetectionVo();
        averagedVo.setOilType(oilType + "平均值");
        for (Map.Entry<String, Double> entry : sumMap.entrySet()) {
            String fieldName = entry.getKey();
            Double sumValue = entry.getValue();
            double averageValue = sumValue / count;
            // 设置平均值到 averagedVo 对象中
            setAverageField(averagedVo, fieldName, averageValue);
        }
        return averagedVo;
    }

    // 设置平均值到对象中
    private void setAverageField(OilSampleDetectionVo vo, String fieldName, double value) {
        try {
            Field field = OilSampleDetectionVo.class.getDeclaredField(fieldName);
            field.setAccessible(true);
            // 获取字段的类型
            Class<?> fieldType = field.getType();
            if (fieldType == Double.class || fieldType == double.class) {
                // 如果字段类型是 Double，则直接设置值
                field.set(vo, value);
            } else if (fieldType == String.class) {
                // 如果字段类型是 String，则将 Double 值转换为 String 后设置
                field.set(vo, String.valueOf(value));
            } else {
                // 其他情况，可能需要根据实际需求进行处理
                System.out.println("Unsupported field type: " + fieldType);
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    // 累加各字段的值
    private void accumulateFields(OilSampleDetectionVo vo, Map<String, Double> sumMap) {
        // 定义需要排除的字段列表
        List<String> excludeFields = Arrays.asList("oilData", "oilId", "oilType");

        // 遍历对象的字段
        Field[] fields = OilSampleDetectionVo.class.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            String fieldName = field.getName();

            // 如果字段名不在排除列表中且以 "oil" 开头，则执行累加操作
            if (fieldName.startsWith("oil") && !excludeFields.contains(fieldName)) {
                try {
                    Object valueObj = field.get(vo);
                    if (valueObj != null) {
                        // 提取数字部分并转换为 Double 类型
                        Double value = extractAndParseDouble(valueObj.toString());
                        sumMap.put(fieldName, sumMap.getOrDefault(fieldName, 0.0) + value);
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    // 提取数字部分并转换为 Double 类型
    private Double extractAndParseDouble(String value) {
        // 使用正则表达式提取数字部分
        Pattern pattern = Pattern.compile("\\d+(\\.\\d+)?");
        Matcher matcher = pattern.matcher(value);
        if (matcher.find()) {
            String number = matcher.group();
            // 将提取的数字转换为 Double 类型
            return Double.valueOf(number);
        }
        return 0.0; // 如果没有找到数字，则返回 0.0
    }
}
